/****************************************************************************
 *
 * Copyright (C) 2003-2008 Los Alamos National Security, LLC
 *                         Packet Analytics Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License Version 2 as
 * published by the Free Software Foundation.  You may not use, modify or
 * distribute this program under any other version of the GNU General
 * Public License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 ****************************************************************************/
package nfse.gui.client;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.gwtext.client.widgets.*;
import com.gwtext.client.widgets.event.*;
import com.gwtext.client.data.*;    
import com.gwtext.client.widgets.grid.CheckboxSelectionModel;
import com.gwtext.client.widgets.grid.ColumnConfig;  
import com.gwtext.client.widgets.grid.ColumnModel;  
import com.gwtext.client.widgets.grid.GridPanel;  
import com.gwtext.client.widgets.grid.event.*;
import com.gwtext.client.widgets.grid.*;
import com.gwtext.client.widgets.layout.*; 
import com.gwtext.client.core.EventObject; 
import com.gwtext.client.core.*;
import com.gwtext.client.util.Format; 

import nfse.gui.query.QuerySummary;
import java.util.*;

//public class SearchResultsPanel extends com.google.gwt.user.client.ui.FlexTable
public class SearchResultsPanel extends Panel
{

	   private HashMap checkedMyQueriesIDs = new HashMap(10);

	    private GridPanel grid = null;
	    
	    NetFSEClient client = null;
	    SearchAnalysisTab searchAnalysisTab = null;
	    final CheckboxSelectionModel cbSelectionModel = new CheckboxSelectionModel();
	    private final Panel buttonPanel = new Panel();    
	    
	    private final Button openButton = new Button("Open");
	    private final Button deleteButton = new Button("Delete");
	    private final Button refreshButton = new Button("Refresh");	  
	    private final Button mergeButton = new Button("Merge");
	    private final Button mkPermButton = new Button("Make Permanent");
	    public boolean refreshGridNow = false;
	    
	    
	    public SearchResultsPanel(NetFSEClient client)
	    {
			this.client = client;
			this.setTitle("Results");	
			this.setClosable(false);
			this.setAutoWidth(true);
			this.setLayout(new FitLayout());
			grid = new GridPanel();
			grid.setStripeRows(true);
			grid.setAutoWidth(true);
			grid.setAutoScroll(true);  
			grid.setEnableColumnResize(true);  
			grid.setEnableDragDrop(false);  
			grid.setEnableColumnHide(false);  
			grid.setEnableColumnMove(true);  
			grid.setAutoExpandColumn(2);
			grid.setAutoExpandMin(150);
			
			myQueries();
	    }
	    
	    public SearchResultsPanel(NetFSEClient client,SearchAnalysisTab searchAnalysisTab) 
	    {
	        this.client = client;
	        this.searchAnalysisTab = searchAnalysisTab;			
			this.setTitle("Results");
			

	        myQueries();
	    }

	    private synchronized void deleteQueries(String[] queryIDs) {

	        String msg = "";
	        if (queryIDs.length == 1) {
	            msg = "Are you sure you want to delete the Search Result for Search " + queryIDs[0] + "?";
	        } else {
	            msg = "The folowing Search Results will be deleted: ";
	            for (int i = 0; i < queryIDs.length; i++) {
	                msg += queryIDs[i];
	                if (i != queryIDs.length - 1) {
	                    msg += ", ";
	                }
	            }
	            msg += ".\n Are you sure you want to delete these Search Results?";
	        }
	        final String[] tempQueryIDs = queryIDs;
	        MessageBox.confirm("Confirm", msg, new MessageBox.ConfirmCallback() {
	            public void execute(String btnID) {
	                if (btnID.equals("yes")) {
	                    QueryServiceAsync NetFSEService = (QueryServiceAsync) GWT.create(QueryService.class);

	                    ServiceDefTarget endpoint = (ServiceDefTarget) NetFSEService;
	                    endpoint.setServiceEntryPoint(NetFSEClient.QUERY_URL);

	                    AsyncCallback callback = new AsyncCallback() {
	                        public void onFailure(Throwable caught) {
	                            NetFSEClient.redirect("NetFSEClient.html");
	                        }

	                        public void onSuccess(Object result) {
	                            Vector temp = new Vector();
	                            Iterator it = checkedMyQueriesIDs.keySet().iterator();
	                            while (it.hasNext()) 
	                            {
	                                String qid = (String) it.next();
	                                temp.addElement(qid);
	                            }
	                            for (int i = 0; i < temp.size(); i++) {
	                                checkedMyQueriesIDs.remove(temp.elementAt(i));
	                            }
	                            myQueries();	                            
	                        }
	                    };

	                    NetFSEService.multiDelete(tempQueryIDs, callback);
	                }
	            }
	        });

	    }



	    private void makePermanent(String[] queryIDs) {

	        if (NetFSEClient.IS_TEST_DRIVE) {
	            MessageBox.alert("Make Permanent is disabled for the Test Drive. Sorry!");
	            return;
	        }

	        String msg = "";
	        if (queryIDs.length == 1) {
	            msg = "Are you sure you want to make Search Results for Search " + queryIDs[0] + " permanent?";
	        } else {
	            msg = "The folowing Search Results will be made permanent: ";
	            for (int i = 0; i < queryIDs.length; i++) {
	                msg += queryIDs[i];
	                if (i != queryIDs.length - 1) {
	                    msg += ", ";
	                }
	            }
	            msg += ".\n Are you sure you want to make these Search Results permanent?";
	        }
	        final String[] tempQueryIDs = queryIDs;
	        MessageBox.confirm("Confirm", msg, new MessageBox.ConfirmCallback() {
	            public void execute(String btnID) {
	                if (btnID.equals("yes")) {
	                    QueryServiceAsync NetFSEService = (QueryServiceAsync) GWT.create(QueryService.class);

	                    ServiceDefTarget endpoint = (ServiceDefTarget) NetFSEService;
	                    endpoint.setServiceEntryPoint(NetFSEClient.QUERY_URL);

	                    AsyncCallback callback = new AsyncCallback() {
	                        public void onFailure(Throwable caught) {
	                            NetFSEClient.redirect("NetFSEClient.html");
	                        }

	                        public void onSuccess(Object result) {
	                            myQueries();
	                        }
	                    };

	                    NetFSEService.multiMakePermanent(tempQueryIDs, callback);
	                }
	            }
	        });
	    }

	    private synchronized void mergeQueries(String[] queryIDs) {

	        String msg = "";
	        if (queryIDs.length == 1) {
	            MessageBox.alert("You must select more than one Search Result to perform a merge.");
	            return;
	        } else {
	            msg = "The folowing Search Results will be merged into Search " + queryIDs[0] + ": ";
	            for (int i = 1; i < queryIDs.length; i++) {
	                msg += queryIDs[i];
	                if (i != queryIDs.length - 1) {
	                    msg += ", ";
	                }
	            }
	            msg += ".\n Are you sure you want to merge these Search Results?";
	        }

	        final String[] tempQueryIDs = queryIDs;
	        MessageBox.confirm("Confirm", msg, new MessageBox.ConfirmCallback() {
	            public void execute(String btnID) {
	                if (btnID.equals("yes")) {
	                    QueryServiceAsync NetFSEService = (QueryServiceAsync) GWT.create(QueryService.class);

	                    ServiceDefTarget endpoint = (ServiceDefTarget) NetFSEService;
	                    endpoint.setServiceEntryPoint(NetFSEClient.QUERY_URL);

	                    AsyncCallback callback = new AsyncCallback() {
	                        public void onFailure(Throwable caught) {
	                            NetFSEClient.redirect("NetFSEClient.html");
	                        }

	                        public void onSuccess(Object result) {
	                            MessageBox.alert((String) result);
	                            myQueries();
	                        }
	                    };
	                    NetFSEService.merge(tempQueryIDs, callback);
	                    myQueries();
	                }
	            }
	        });

	    }

	    
	    public String[] getSelectedQueryIds()
	    {
	    	Record[] records = cbSelectionModel.getSelections();
	    	String[] queryIds = new String[records.length];
            for (int x = 0; x < records.length; x++)
            {
           	 System.out.println("The query id is " + records[x].getAsString("Search Id"));
           	 queryIds[x] = records[x].getAsString("Search Id");           	 
            }
            
            return queryIds;
	    }
	    
	    public QuerySummary[] querySummaryData;
	    
	    public QuerySummary[] getQuerySummary()
	    {
	    	return querySummaryData;
	    }
	    
	    public void setQuerySummaryData(QuerySummary[] querySummaryData)
	    {
	    	this.querySummaryData = querySummaryData;
	    }
	    
	    //public synchronized void myQueries() {
	    public void myQueries() 
	    {
	        QueryServiceAsync nfseService = (QueryServiceAsync) GWT.create(QueryService.class);

	        ServiceDefTarget endpoint = (ServiceDefTarget) nfseService;
	        endpoint.setServiceEntryPoint(NetFSEClient.QUERY_URL);

	        AsyncCallback callback = new AsyncCallback() 
	        {
	            public void onFailure(Throwable caught) 
	            {
	                NetFSEClient.redirect("NetFSEClient.html");
	            }
	            public void onSuccess(Object result) 
	            {
	                QuerySummary[] summaries = (QuerySummary[]) result;
	                setQuerySummaryData(summaries);
	                if (refreshGridNow)
	                {
	                	refreshGrid();
	                	refreshGridNow = false;
	                }
	                else
	                	checkForBuild();
	            }
	        };

	        nfseService.myQueries(callback);
	    }

	    public void checkForBuild()
	    {
	    	if (searchAnalysisTab != null)
	    	{
	    		//searchAnalysisTab.checkIfReadyToBuild(this);
	    	}	    		
	    	else
	    		client.checkIfReadyToBuild(this);
	    }

	    

		
		public void openQueries(String[] queryIds)
		{
			System.out.println("Get the queries and send the user to the Analysis Panel");

			//Need to get the types for this specific query.
			
			client.analysisPanelGroup.addQueryTabPanels(queryIds);
			//client.tabs.selectTab(2);
			client.tabs.activate(3);
		}
		
		public void buildPanel()
	    {
	    	buttonPanel.setBaseCls("button-panel");
	    	buttonPanel.setAutoWidth(true);
	    	
	    	//Calling the next line kills the button panel. The button panel does not show up. Don't ask me why. 
	    	//System.out.println("The styles are " + buttonPanel.getStyleName(buttonPanel.getElement()));
	    	openButton.addListener( new ButtonListenerAdapter() 
	    		{  
	    			Record[] records;
	    			String[] queryIds;
	    		             public void onClick(Button button, EventObject e) 
	    		             {
					             records = cbSelectionModel.getSelections();
					             queryIds = new String[records.length];
					             for (int x = 0; x < records.length; x++)
					             {
					            	 System.out.println("The query id is " + records[x].getAsString("Search Id"));
					            	 queryIds[x] = records[x].getAsString("Search Id");
					            	 
					             }
	    		            	 
	    			             if (records.length > 5)
	    			             {					            	 
	    			            	MessageBox.confirm("Open Query Limitation", "Opening more than 5 Queries may be slow. Are you sure you want to open this many?",  
	    			            	               new MessageBox.ConfirmCallback() 
	    			            					{  
	    			            	                          public void execute(String btnID) 
	    			            	                          {  
	    			            			                          if (btnID.equals("yes"))
	    			            			                          {
	    			            			                        	  List noResultsList = new ArrayList();	  
	    			            			                        	  for (int x = 0; x < queryIds.length; x++)
	    			            			                        	  {
	    			            			                        		  if (!checkIfQueryHasResults(queryIds[x]))
	    			            			                        			  noResultsList.add(queryIds[x]);
	    			            			                        	  }
	    			            			                        	  
	    			            			                        	  if (noResultsList.size() > 0)
	    			            			                        	  {
	    			            			                        		  String message = "The following query ids do not have results: ";
	    			            			                        		  for (int z = 0; z < noResultsList.size(); z++)
	    			            			                        			  message += noResultsList.get(z) + " ";
	    			            			                        		  
	    			            			                        		  MessageBox.alert("Queries Have No Results", message);
	    			            			                        		  
	    			            			                        	  }
	    			            			                        	  else
	    			            			                        	  {
	    			            			                        		  openQueries(queryIds);
	    			            			                        	  }
	    			            			                        	  
	    			            			                          }	    			            			                        	  
	    			            			                          else
	    			            			                        	  System.out.println("Decided not to go to the analysis panel. Probably too many queries");		                        	  					            			                        	  
	    			            	                          }  
	    			            			          });  					            	 					            	 					            	
	    			             }
					             else
					             {
		                        	  List noResultsList = new ArrayList();	  
		                        	  for (int x = 0; x < queryIds.length; x++)
		                        	  {
			                        		  if (!checkIfQueryHasResults(queryIds[x]))
			                        			  noResultsList.add(queryIds[x]);
		                        	  }
			                        	  
		                        	  if (noResultsList.size() > 0)
		                        	  {
		                        		  String message = "The following query ids do not have results: ";
		                        		  for (int z = 0; z < noResultsList.size(); z++)
		                        			  message += noResultsList.get(z) + " ";
		                        		  
		                        		  MessageBox.alert("Queries Have No Results", message);
		                        	  }
		                        	  else
		                        	  {
		                        		  openQueries(queryIds);
		                        	  }
					             }

	    		             }
	    		}
	    	);	    	
	    	buttonPanel.addButton(openButton);
	    	refreshButton.addListener( new ButtonListenerAdapter() 
		    	{  
		    		             public void onClick(Button button, EventObject e) 
		    		             {
		    		            	 refreshGridNow = true;
		    		            	 myQueries();		    		            		
		    		             }
		    	}
	    	);	    	
	    	buttonPanel.addButton(refreshButton);
	    	
	    	deleteButton.addListener( new ButtonListenerAdapter() 
		    	{  
		    		             public void onClick(Button button, EventObject e) 
		    		             {		    		            	 
		    		            	 String[] queryIds = getSelectedQueryIds();
		    		            	 if (queryIds != null)
		    		            	 {
		    		            		 refreshGridNow = true;
		    		            		 deleteQueries(queryIds);
		    		            	 }		    		            	 
		    		             }
		    		             
		    	}
            );	    	
	    	buttonPanel.addButton(deleteButton);
	    	
			mergeButton.addListener( new ButtonListenerAdapter() 
				{  
					             public void onClick(Button button, EventObject e) 
					             {
		    		            	 String[] queryIds = getSelectedQueryIds();
		    		            	 if (queryIds != null)
		    		            	 {
		    		            		 refreshGridNow = true;
		    		            		 mergeQueries(queryIds);
		    		            	 }		    						            	 
					             }
				}
		    );	    	
        	buttonPanel.addButton(mergeButton);

        	mkPermButton.addListener( new ButtonListenerAdapter() 
	        	{  
	    		             public void onClick(Button button, EventObject e) 
	    		             {
	    		            	 String[] queryIds = getSelectedQueryIds();
	    		            	 if (queryIds != null)
	    		            	 {
	    		            		 refreshGridNow = true;
	    		            		 makePermanent(queryIds);
	    		            	 }		    						            	 
	    		             }
	        	}
        	);	    	
	        buttonPanel.addButton(mkPermButton);
	    	
	        buttonPanel.setButtonAlign(Position.LEFT);
	    	Panel gridHolder = new Panel();
	    	gridHolder.setLayout(new BorderLayout());
	    	gridHolder.add(createResultGrid(),new BorderLayoutData(com.gwtext.client.core.RegionPosition.CENTER));
	    	gridHolder.add(buttonPanel,new BorderLayoutData(com.gwtext.client.core.RegionPosition.NORTH));
		    this.add(gridHolder);
	    }
	    
	    
		public boolean checkIfQueryHasResults(String queryIds)
		{
			for (int x = 0; x < querySummaryData.length; x++)
			{
					if (querySummaryData[x].queryID.equals(queryIds))
					{
						if (querySummaryData[x].status == 1)
						{
							if (querySummaryData[x].count <= 0)
								return false;
						}
					}					
			}
			return true;
			
		}
		
		
		public void refreshGrid()
		{
			
	    	setColumnNameList();
			Object[][] data = convertRawDataToObjectGrid();

			//The columns names are not determined until after the data Object[][] has been processed
			RecordDef recordDef = buildRecordDef();

			if (data != null)
			{
				MemoryProxy proxy = new MemoryProxy(data);
				
				ArrayReader reader = new ArrayReader(recordDef);
				Store store = new Store(proxy,reader);
				store.load();		
				 grid.reconfigure(store, getColumnModel());	
			}
		}
		
	    public GridPanel createResultGrid()
	    {
	    	setColumnNameList();
			Object[][] data = convertRawDataToObjectGrid();

			//The columns names are not determined until after the data Object[][] has been processed
			RecordDef recordDef = buildRecordDef();
			
			
			if (data != null)
			{
				MemoryProxy proxy = new MemoryProxy(data);
				
				ArrayReader reader = new ArrayReader(recordDef);
				Store store = new Store(proxy,reader);
				store.load();
				grid.setStore(store);		
			}
			
	 
			ColumnModel columnModel = getColumnModel();
			
			 grid.setColumnModel(columnModel);  
			 grid.setSelectionModel(cbSelectionModel);
			 			
			 grid.addGridRowListener(new GridRowListener() 
			 {
				             public void onRowClick(GridPanel grid, int rowIndex, EventObject e) 
				             {  
					             System.out.println(Format.format("GridRowListener.onRowClick::rowIndex({0})", rowIndex));		
					             
				             }
				             
				             public void onRowDblClick(GridPanel grid, int rowIndex, EventObject e) 
				             {  
				                 System.out.println(Format.format("GridRowListener.onRowDblClick::rowIndex({0})", rowIndex));
					             Record record = cbSelectionModel.getSelected();
					             System.out.println("The value the query id in the double clicked row is " + record.getAsString("Search Id"));
					             
					             
				             } 
				             
				             public void onRowContextMenu(GridPanel grid, int rowIndex, EventObject e) 
				             {  
				                 System.out.println(Format.format("GridRowListener.onRowContextMenu::rowIndex({0}), ({1}), y({2})", rowIndex, e.getPageX(), e.getPageY()));  
				             } 
				             
			 });
			 
			    			    
			  return grid;
	    }
	    
		private RecordDef buildRecordDef()
		{	
			FieldDef[] sfd = new StringFieldDef[columnNameList.size()];
			
			
			for (int i = 0; i < columnNameList.size(); i++)
			{
				sfd[i] = new StringFieldDef((String)columnNameList.get(i));
			}					
			
			RecordDef recordDef = new RecordDef(sfd);

			return recordDef;
		}
		
		
		private ColumnModel getColumnModel()
		{
			BaseColumnConfig[] columnConfig;
			
			if (columnNameList.size() == 0)			
			    columnConfig = new BaseColumnConfig[columnNameList.size() + 2];
			else
				columnConfig = new BaseColumnConfig[columnNameList.size() + 1];
			
			 			
				if (columnNameList.size() == 0)
				{
					ColumnConfig ccNoData = new ColumnConfig("NetFlow","NetFlow",100);
					columnConfig[1] = ccNoData;
				}
				
				columnConfig[0] = new CheckboxColumnConfig(cbSelectionModel);
				
				for (int i = 0; i < columnNameList.size(); i++)
				{
					
					int width = 100;
					if (i == 2)
						width = 150;
					if (i == 1)
						width = 250;

					ColumnConfig cc = new ColumnConfig((String)columnNameList.get(i),(String)columnNameList.get(i),width);
					//cc.setAlign(TextAlign.RIGHT);
					columnConfig[i + 1] = cc;
				}					

				 ColumnModel columnModel = new ColumnModel(columnConfig);

			return columnModel;
		}
		
		private void setColumnNameList()
		{
			if (querySummaryData != null)
			{			
				columnNameList = new ArrayList();
				columnNameList.add("Search Id");
				columnNameList.add("Note");
				columnNameList.add("Expires");
				columnNameList.add("Status");
				int[] typeIds = client.getAllTypes();
				
				for (int i = 0; i < typeIds.length; i++)
				{
					columnNameList.add(client.getTypeName(typeIds[i]));			
				}
			}
		}
		
		private ArrayList columnNameList;
		
		/**
		 * This converts the incoming data object a HashMap or an ArrayList into a Object[][]
		 */
		private Object[][] convertRawDataToObjectGrid()
		{
			int columns = columnNameList.size() + 1;
			
			Object[][] displayData = null;
			
			if (querySummaryData != null)
			{
				displayData = new Object[querySummaryData.length][columns];
				
				QuerySummary qs = null;
				int recordCount = 0;
				for (int i = 0; i < querySummaryData.length; i++)
				{
					int recordCol = 0;
					qs = querySummaryData[i];
					displayData[recordCount][recordCol++] = qs.queryID;
					displayData[recordCount][recordCol++] = qs.note;
					displayData[recordCount][recordCol++] = qs.ts + "";
					displayData[recordCount][recordCol++] = qs.status + "";
					for (int j = 0; j < client.getAllTypes().length; j++)
					{
						displayData[recordCount][recordCol++] = qs.getTypeCount(client.getAllTypes()[j]) + "";
					}								
					recordCount++;
				}					
				
			}
			else
			{
				displayData = new Object[1][1];
			}
			
			return displayData;
		}
}
